package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"
	"syscall"
)

func main() {

	for {

		var userName string = os.Getenv("USER")
		// var hostName string = "ts" // tinyShell
		var env []string = os.Environ()

		pwd, err := os.Getwd()
		if err != nil {
			log.Println(err.Error())
		}

		// fmt.Printf("%s:%s$", userName, hostName)
		fmt.Printf("%s:$", userName)

		// 读入一行，`\n`结束;
		inputReader := bufio.NewReader(os.Stdin)
		input, err := inputReader.ReadString('\n')
		if err != nil {
			log.Printf("[args error]:%s", err.Error())
			continue
		}

		// 依照空格分成多个参数;
		shellArgs := strings.Fields(input)
		if len(shellArgs) == 0 {
			continue
		}

		// 退出tinyShell
		if len(shellArgs) == 1 && shellArgs[0] == "quit" || shellArgs[0] == "q" {
			break
		}

		// cd command;
		if shellArgs[0] == "cd" {
			if len(shellArgs) == 1 {
				syscall.Chdir("/")
				continue
			} else if len(shellArgs) == 2 {
				err := syscall.Chdir(pwd + "/" + shellArgs[1])
				if err != nil {
					syscall.Chdir("/")
				}
				continue
			} else {
				fmt.Println("[args error]")
				continue
			}
		} // cd end;

		// find command path;
		commandPath, err := exec.LookPath(shellArgs[0])
		if err != nil {
			log.Printf("[no command error]- %s", err.Error())
			continue
		} // end;

		// handle redirect
		// 如果有有重定向，shellArgs为实际命令，reDirect 是重定向文件
		// 重定向应该只有一次，即 `>`,`<`,`>>`,`<<` 最多出现一次
		// TODO: check whether reDirect appear once.
		var direction string
		var reDirect []string
		for index, arg := range shellArgs {
			if arg == ">" || arg == "<" || arg == ">>" || arg == "<<" {
				direction = arg
				reDirect = shellArgs[index+1:]
				shellArgs = shellArgs[0:index]
				break
			}
		}
		if len(reDirect) > 1 {
			fmt.Println("[err args]")
			continue
		}
		// handle pipe

		pid, _, _ := syscall.Syscall(syscall.SYS_FORK, 0, 0, 0)
		if pid == 0 {

			if direction == ">" || direction == ">>" {
				var file *os.File
				var flag int
				if direction == ">" {
					flag = os.O_WRONLY | os.O_CREATE | os.O_TRUNC | os.O_SYNC
				} else if direction == ">>" {
					flag = os.O_APPEND | os.O_WRONLY | os.O_CREATE | os.O_SYNC
				}
				file, err := os.OpenFile(reDirect[0], flag, 0777)
				if err != nil {
					log.Println("[open file err] - ", err.Error())
				}
				cmd := exec.Command(shellArgs[0], shellArgs[1:]...)
				cmd.Stdout = file
				cmd.Start()
			} else if direction == "<" || direction == "<<" {
				// TODO
				var file *os.File
				if direction == "<" {
					// TODO: 需要判断`<` 重定向符号的右侧是字符串还是文件？
					file, _ = os.OpenFile(reDirect[0], os.O_RDONLY, 0777)
				} else if direction == "<<" {
					// TODO:这个有点复杂？
				}
				cmd := exec.Command(shellArgs[0], shellArgs[1:]...)
				cmd.Stdin = file
				cmd.Start()
			} else {
				syscall.Exec(commandPath, shellArgs, env)
			}

			os.Exit(0)
		} else {
			syscall.Syscall(syscall.SYS_WAIT4, 0, 0, 0)
		}
	}
}
